package com.wrt.wm.service.impl;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.Base64;
import java.util.UUID;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.wrt.wm.entity.AjaxResult;
import com.wrt.wm.entity.FontParameters;
import com.wrt.wm.entity.ResultImageInfo;
import com.wrt.wm.service.WaterMarkService;
import com.wrt.wm.util.DeleteFileUtil;
import com.wrt.wm.util.JudgeImageUtil;
import com.wrt.wm.util.RewriteImageUtil;
import com.wrt.wm.util.WaterMarkUtil;

import lombok.extern.log4j.Log4j2;
import net.coobird.thumbnailator.geometry.Positions;

@Service
@Log4j2
public class WaterMarkServiceImpl implements WaterMarkService {
	
	@Value("${temppath.source:temp_source}")
	private String sourcepath;

	@Autowired
	private JudgeImageUtil ji;
	@Autowired
	private RewriteImageUtil ri;
	@Autowired
	private WaterMarkUtil wmu;
	@Autowired
	private DeleteFileUtil deleteFile;

	@Override
	public AjaxResult addWordMark(MultipartFile file, String waterMarkContent, FontParameters fontParameters) {
		// 带有后缀（格式）的文件名
		String filename = file.getOriginalFilename();
		// 文件后缀（格式）
		String ext = FilenameUtils.getExtension(filename).toLowerCase();
		// 无后缀的文件名
		String filebasename = handleFileName(FilenameUtils.getBaseName(filename));
		File temp = multipartFileToFile(file, ext);
		AjaxResult judgeresult = ji.isImage(temp);
		if (judgeresult.getCode() == 0) {
			String srcImg = ri.handle(judgeresult.getMsg(), temp, (BufferedImage) judgeresult.getData());
			File srcImgFile = new File(srcImg);
			if (!srcImgFile.exists()) {
				return AjaxResult.fail("图片重绘失败");
			}
			wmu.setFontParam(fontParameters);
			String outImg = wmu.mark(srcImg, waterMarkContent);
			File outImgFile = new File(outImg);
			if (!outImgFile.exists()) {
				return AjaxResult.fail("水印添加失败");
			}
			deleteFile.cleanUp(temp, srcImgFile);
			String imgname = String.valueOf(filebasename) + "_wm." + ext;
			ResultImageInfo rii = new ResultImageInfo(file2base64(outImgFile), ext, imgname);
			return AjaxResult.success("处理完成", rii);
		} else {
			deleteFile.cleanUp(temp);
			return judgeresult;
		}
	}
	
	@Override
	public AjaxResult addImgMark(MultipartFile srcfile, MultipartFile wmfile, String pname, Float alpha) {
		String filename = srcfile.getOriginalFilename();
		String ext = FilenameUtils.getExtension(filename).toLowerCase();
		String filebasename = handleFileName(FilenameUtils.getBaseName(filename));
		File srctemp = multipartFileToFile(srcfile, ext);
		File wmtemp = multipartFileToFile(wmfile,
				FilenameUtils.getExtension(wmfile.getOriginalFilename()).toLowerCase());
		AjaxResult handleresult = rewrite2Img(srctemp, wmtemp);
		if (handleresult.getCode() == 0) {
			Positions position = getPosition(pname);
			String[] imgs = (String[]) handleresult.getData();
			String outImg = wmu.mark(imgs[0], imgs[1], position, alpha);
			File outImgFile = new File(outImg);
			if (!outImgFile.exists()) {
				return AjaxResult.fail("水印添加失败");
			}
			deleteFile.cleanUp(srctemp, new File(imgs[0]), wmtemp, new File(imgs[1]));
			String imgname = String.valueOf(filebasename) + "_wm." + ext;
			ResultImageInfo rii = new ResultImageInfo(file2base64(outImgFile), ext, imgname);
			return AjaxResult.success("处理完成", rii);
		} else {
			return handleresult;
		}
	}

	/**
	 * 
	 * 处理文件名称，移除特殊符号
	 * 
	 * @param filename 图片文件名
	 * 
	 * @return 处理后的文件名
	 *
	 */
	private String handleFileName(String filename) {
		StringBuilder sbu = new StringBuilder();
		char[] chars = filename.toCharArray();
		for (int i = 0; i < chars.length; i++) {
			int temp = chars[i];
			if (judgeNormal(temp)) {
				sbu.append(Character.valueOf(chars[i]));
			}
		}
		return sbu.toString();
	}
	
	/**
	 * 
	 * 判断字符是否属于常规字符
	 * @param parseChar 待判断的字符
	 * 
	 * @return true-属于常规字符;false-特殊字符
	 *
	 */
	private boolean judgeNormal(int parseChar) {
		boolean result = false;
		int[] min = { 33, 39, 44, 48, 62, 65, 91, 93, 95, 97, 8212, 8216, 8220, 8230, 12304, 12289, 12298, 19968, 65281,
				65288, 65292, 65306, 65311 };
		int[] max = { 34, 41, 46, 60, 63, 90, 91, 93, 95, 122, 8212, 8217, 8221, 8230, 12305, 12289, 12299, 40895,
				65281, 65289, 65292, 65307, 65311 };
		for (int i = 0; i < min.length; i++) {
			if (min[i] <= parseChar && parseChar <= max[i]) {
				result = true;
				break;
			}
		}
		return result;
	}

	/**
	 * 
	 * MultipartFile对象转换为File对象
	 * 
	 * @param mfile MultipartFile对象
	 * @param suffix 文件后缀名
	 * 
	 * @return File对象
	 *
	 */
	private File multipartFileToFile(MultipartFile mfile, String suffix) {
		File sourceDir = new File(sourcepath);
		if (!sourceDir.exists()) {
			sourceDir.mkdir();
		}
		File file = new File(sourcepath + File.separator + UUID.randomUUID().toString() + "." + suffix);
		try (InputStream ins = mfile.getInputStream(); OutputStream os = new FileOutputStream(file);) {
			int bytesRead = 0;
			int limitbyte = 8192;
			byte[] buffer = new byte[limitbyte];
			while ((bytesRead = ins.read(buffer, 0, limitbyte)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
		} catch (Exception e) {
			log.info("输入流转换文件对象出错", e);
		}
		return file;
	}
	
	/**
	 * 
	 * 图片文件转换为base64字符串
	 * 
	 * @param file 图片文件对象
	 * 
	 * @return base64字符串
	 * 
	 */
	private String file2base64(File file) {
		try {
			byte[] b = Files.readAllBytes(file.toPath());
			this.deleteFile.cleanUp(file);
			return Base64.getEncoder().encodeToString(b);
		} catch (IOException e) {
			this.deleteFile.cleanUp(file);
			log.error(e.getMessage(), e);
			return null;
		}
	}
	
	/**
	 * 
	 * 重绘两个图片（图片水印）
	 * 
	 * @param srctemp 待处理的文件对象
	 * @param wmtemp 水印图片文件对象
	 * 
	 * @return 封装后的结果
	 *
	 */
	private AjaxResult rewrite2Img(File srctemp, File wmtemp) {
		AjaxResult judgesrc = ji.isImage(srctemp);
		if (judgesrc.getCode() == 0) {
			AjaxResult judgewm = ji.isImage(wmtemp);
			if (judgewm.getCode() == 0) {
				String srcImg = ri.handle(judgesrc.getMsg(), srctemp, (BufferedImage) judgesrc.getData());
				File srcImgFile = new File(srcImg);
				if (!srcImgFile.exists()) {
					return AjaxResult.fail("原图片重绘失败");
				}
				String wmImg = ri.handle(judgewm.getMsg(), wmtemp, (BufferedImage) judgewm.getData());
				File wmImgFile = new File(wmImg);
				if (!wmImgFile.exists()) {
					return AjaxResult.fail("水印图片重绘失败");
				}
				String[] imgs = { srcImg, wmImg };
				return AjaxResult.success(null, imgs);
			} else {
				deleteFile.cleanUp(wmtemp);
				return judgewm;
			}
		} else {
			deleteFile.cleanUp(srctemp);
			return judgesrc;
		}
	}

	/**
	 * 
	 * 获取水印位置（图片水印）
	 * 
	 * @param pname 位置枚举名称
	 * 
	 * @return 位置枚举项（默认居中）
	 *
	 */
	private Positions getPosition(String pname) {
		if (StringUtils.isBlank(pname)) {
			return Positions.CENTER;
		} else {
			return Positions.valueOf(pname);
		}
	}
}
